/**
 * 流式API处理工具
 */

export interface StreamMessage {
  event: string
  task_id?: string
  message_id?: string
  conversation_id?: string
  answer?: string
  created_at?: number
  metadata?: any
  usage?: any
  retriever_resources?: any[]
}

export interface StreamingOptions {
  onMessage?: (message: StreamMessage) => void
  onError?: (error: any) => void
  onComplete?: () => void
  onStart?: () => void
}

/**
 * 处理流式响应
 */
export class StreamingHandler {
  private reader: ReadableStreamDefaultReader<Uint8Array> | null = null
  private decoder = new TextDecoder()
  private buffer = ''

  constructor(private options: StreamingOptions = {}) {}

  /**
   * 开始处理流式响应
   */
  async handleStream(response: Response) {
    if (!response.body) {
      throw new Error('Response body is null')
    }

    this.reader = response.body.getReader()
    this.options.onStart?.()

    try {
      while (true) {
        const { done, value } = await this.reader.read()
        
        if (done) {
          this.processBuffer()
          this.options.onComplete?.()
          break
        }

        // 解码数据并添加到缓冲区
        const chunk = this.decoder.decode(value, { stream: true })
        this.buffer += chunk
        
        // 处理缓冲区中的完整消息
        this.processBuffer()
      }
    } catch (error) {
      this.options.onError?.(error)
    } finally {
      this.cleanup()
    }
  }

  /**
   * 处理缓冲区中的消息
   */
  private processBuffer() {
    const lines = this.buffer.split('\n')
    this.buffer = lines.pop() || '' // 保留最后一行（可能不完整）

    for (const line of lines) {
      if (line.trim() === '') continue
      
      // 处理 SSE 格式的数据
      if (line.startsWith('data: ')) {
        const data = line.slice(6).trim()
        
        if (data === '[DONE]') {
          this.options.onComplete?.()
          continue
        }

        try {
          const message: StreamMessage = JSON.parse(data)
          this.options.onMessage?.(message)
        } catch (error) {
          console.warn('Failed to parse SSE message:', data, error)
        }
      }
    }
  }

  /**
   * 停止流式处理
   */
  stop() {
    this.cleanup()
  }

  /**
   * 清理资源
   */
  private cleanup() {
    if (this.reader) {
      this.reader.cancel()
      this.reader = null
    }
    this.buffer = ''
  }
}

/**
 * 发送流式请求
 */
export async function sendStreamingRequest(
  url: string,
  data: any,
  options: StreamingOptions = {},
  headers: Record<string, string> = {}
) {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...headers
    },
    body: JSON.stringify(data)
  })

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`)
  }

  const handler = new StreamingHandler(options)
  await handler.handleStream(response)
}

/**
 * 创建流式消息处理器
 */
export function createStreamingHandler(options: StreamingOptions) {
  return new StreamingHandler(options)
}

/**
 * 解析 Dify 流式响应
 */
export function parseDifyStreamMessage(message: StreamMessage) {
  switch (message.event) {
    case 'message':
      return {
        type: 'message',
        content: message.answer || '',
        messageId: message.message_id,
        conversationId: message.conversation_id,
        timestamp: message.created_at ? new Date(message.created_at * 1000) : new Date()
      }
    
    case 'message_end':
      return {
        type: 'message_end',
        messageId: message.message_id,
        conversationId: message.conversation_id,
        metadata: message.metadata,
        usage: message.usage
      }
    
    case 'error':
      return {
        type: 'error',
        error: message
      }
    
    case 'workflow_started':
      return {
        type: 'workflow_started',
        data: message
      }
    
    case 'workflow_finished':
      return {
        type: 'workflow_finished',
        data: message
      }
    
    case 'node_started':
      return {
        type: 'node_started',
        data: message
      }
    
    case 'node_finished':
      return {
        type: 'node_finished',
        data: message
      }
    
    default:
      return {
        type: 'unknown',
        data: message
      }
  }
}
